#pragma once

#include <string>
#include <iostream>

#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <cstdlib>
#include <unistd.h>

#include "Logger.hpp"

enum{
    SOCK_ERROR = 2,
    BIND_ERROR = 3,
    LISTEN_ERROR = 4
};

class TCPSocket{
public:
    //析构函数
    TCPSocket() : _sockfd(-1){};
    ~TCPSocket(){if(_sockfd > 0) close(_sockfd);}
    
    //创建套接字
    void Sock(){
        // std::cout << "Sock" << std::endl;
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if(_sockfd < 0){
            Log(Fatal, "socket failed");
            exit(SOCK_ERROR);
        }
    }

    //绑定
    void Bind(uint16_t port){
        // std::cout << "Bind" << std::endl;
        struct sockaddr_in serverAddr;
        memset(&serverAddr, 0, sizeof(serverAddr));
        socklen_t lenServer = sizeof(serverAddr);
        serverAddr.sin_addr.s_addr = INADDR_ANY;
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_port = htons(port);

        if(bind(_sockfd, (const struct sockaddr*)&serverAddr, lenServer) < 0){
            Log(Fatal, "bind failed");
            exit(BIND_ERROR);
        }
    }

    //监听
    void Listen(){
        // std::cout << "Listen" << std::endl;
        if(listen(_sockfd, _backlog) < 0){
            Log(Fatal, "listen failed");
            exit(LISTEN_ERROR);
        }
    }

    //Accept
    int Accept(std::string& clientIP, uint16_t& port){
        // std::cout << "Accept" << std::endl;

        struct sockaddr_in clientAddr;
        memset(&clientAddr, 0, sizeof(clientAddr));
        socklen_t clientLen = sizeof(clientAddr);
        int newfd = accept(_sockfd, (struct sockaddr*)&clientAddr, &clientLen);
        if(newfd < 0){
            Log(Warning, "accept failed");
            return -1;
        }
        char IP[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &clientAddr.sin_addr, IP, INET_ADDRSTRLEN);
        clientIP = IP;
        port = ntohs(clientAddr.sin_port);

        return newfd;
    }

    bool Connect(const std::string& IP, uint16_t port){
        // std::cout << "Connect" << std::endl;
        struct sockaddr_in sockaddr;
        memset(&sockaddr, 0, sizeof(sockaddr));
        sockaddr.sin_family = AF_INET;
        if(inet_pton(AF_INET, IP.c_str(), &sockaddr.sin_addr) <= 0)
        {
            std::cerr << "无效IP: " << IP << std::endl;
            return false;
        }
        
        sockaddr.sin_port = htons(port);
        socklen_t len = sizeof(sockaddr);

        if(connect(_sockfd, (const struct sockaddr*)&sockaddr, len) < 0){
            std::cerr << IP << ":" << port << "连接失败!" << std::endl;
            return false;
        }

        return true;
    }

    //关闭fd
    void Close(){
        if(_sockfd > 0){
            close(_sockfd);
            _sockfd = -1;
        }

    }

    //获取socket
    int GetSocket() {return _sockfd;} 

private:
    TCPSocket(const TCPSocket&) = delete;
    TCPSocket& operator=(const TCPSocket&) = delete;
private:
    int _sockfd;
    const int _backlog = 10;
};